from flask import Blueprint, jsonify, request
from app.forms import InitializeAdminForm, LoginForm
from secrets import token_hex
from app.exts import db
from werkzeug.security import generate_password_hash, check_password_hash
from app.models import UserModel, MenuModel, RoleModel
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
from utils import model_to_dict, scalars_to_list
from json import loads

auth = Blueprint('auth', __name__)


@auth.get('/routes')
@jwt_required()
def routes():
    with open(
            'D:/MyFrame/vue-admin-manage/vue-admin-manage-back-end/static/json/routes.json', 'r',
            encoding='utf8'
    ) as file:
        data = loads(file.read())
    id = get_jwt_identity().get('user_id')
    user_query = UserModel.query.get(id)
    # 过滤路由菜单
    menu_query = MenuModel.query.join(RoleModel.menus).filter(RoleModel.id.in_([r.id for r in user_query.roles])).order_by(MenuModel.sort).all()
    # 将ORM对象转换为JSON格式
    menu_data = scalars_to_list(menu_query)
    # 过滤后可以使用的前端 vue 路由
    filter_menu_data = []
    # 不要读，就是为了过滤 vue 路由，很乱，很杂，就是为了拼接前端 vue 路由的
    for m_index in range(len(menu_data)):
        roles = [r_code.code for r_code in menu_query[m_index].roles]
        menu_data[m_index]['meta'] = {}
        menu_data[m_index]['meta']['roles'] = roles
        if menu_data[m_index].get('name'):
            menu_data[m_index]['meta']['title'] = menu_data[m_index].pop('name')
        if menu_data[m_index].get('icon'):
            menu_data[m_index]['meta']['icon'] = menu_data[m_index].pop('icon')
        else:
            menu_data[m_index].pop('icon')
        if menu_data[m_index].get('no_cache'):
            menu_data[m_index]['meta']['noCache'] = menu_data[m_index].pop('no_cache')
        else:
            menu_data[m_index].pop('no_cache')

        if not menu_data[m_index].get('redirect'):
            menu_data[m_index].pop('redirect')

        if menu_data[m_index].get('always_show'):
            menu_data[m_index]['alwaysShow'] = bool(menu_data[m_index].pop('always_show'))
        else:
            menu_data[m_index].pop('always_show')

        if menu_data[m_index].get('hidden'):
            menu_data[m_index]['hidden'] = bool(menu_data[m_index].pop('hidden'))
        else:
            menu_data[m_index].pop('hidden')

        if menu_data[m_index].get('component') != 'Layout':
            menu_data[m_index]['component'] = f'@/views/{menu_data[m_index]["component"]}.vue'

        menu_data[m_index]['name'] = menu_data[m_index].pop('route_name')
        menu_data[m_index].pop('perm')
        menu_data[m_index].pop('sort')

        menu_type = menu_data[m_index].get('type')
        if menu_type != 3:
            filter_menu_data.append(menu_data[m_index])

    # 父子菜单进行拼接
    if not len(filter_menu_data) == 0:
        deleted_list = []
        for num in range(len(filter_menu_data)):
            filter_menu_data[num]['children'] = []
            for item in range(len(filter_menu_data)):
                if filter_menu_data[num]['id'] == filter_menu_data[item]['parent_id']:
                    filter_menu_data[num]['children'].append(filter_menu_data[item])
                    deleted_list.append(filter_menu_data[item]['id'])
            if len(filter_menu_data[num].get('children')) == 0:
                filter_menu_data[num].pop('children')
        # 根据 id 数组删除字典
        for id_to_remove in deleted_list:
            for item in filter_menu_data:
                if item['id'] == id_to_remove:
                    filter_menu_data.remove(item)

    dashboard = loads(
        '{"path":"/","component":"Layout","redirect":"/dashboard","children":[{"path":"dashboard","component":"@/views/dashboard/index","name":"Dashboard","meta":{"title":"首页","icon":"homepage","affix":true}}]}'
    )
    error_404 = loads(
        '{"path":"*","redirect":"/404","hidden":true}'
    )
    filter_menu_data.insert(0, dashboard)
    filter_menu_data.append(error_404)
    # data: 可以将 data=filter_menu_data，换成 data
    return jsonify(code=200, data=filter_menu_data, message='获取成功')


# 超级管理员初始化
@auth.post('/initialize/admin')
def initialize_admin():
    body_json = request.get_json()
    initialize_admin_form = InitializeAdminForm(data=body_json)
    # 表单验证不通过，进入该判断
    if not initialize_admin_form.validate():
        return jsonify({
            'code': 500,
            'data': None,
            'message': initialize_admin_form.errors['password'][0]
        })
    # 获取表单密码
    password = body_json['password']
    # 随机生成密码盐
    salt = token_hex(5)
    # 加盐后的密码
    salt_password = generate_password_hash(password + salt)
    admin_ORM = UserModel.query.filter_by(username='admin').first()
    # 判断超级管理员是否存在，存在更改密码，不存在重新创建
    if admin_ORM:
        admin_ORM.password = salt_password
        admin_ORM.salt = salt
        db.session.commit()
    else:
        users_model = UserModel(
            username='admin',
            password=salt_password,
            salt=salt,
            avatar='https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
            introduction='I am a super administrator',
            name='蜘蛛侠',
            sort=0
        )
        db.session.add(users_model)
        db.session.commit()
    return jsonify(code=200, data=None, message='初始化成功')


# 用户登录
@auth.post('/login')
def login():
    body_json = request.get_json()
    login_form = LoginForm(data=body_json)
    if not login_form.validate():
        # 只取出第一个错误信息并且发送给客户端
        error_first = next(iter(login_form.errors.values()))[0]
        return jsonify(code=400, message=error_first, data=None)
    username = body_json['username']
    password = body_json['password']
    user = UserModel.query.filter_by(username=username).first()
    if not user:
        return jsonify(code=400, message='账号不存在', data=None)
    salt_password = password + user.salt
    if not check_password_hash(user.password, salt_password):
        return jsonify(code=400, message='账号或者密码错误', data=None)
    token = create_access_token(identity={'user_id': user.id})
    return jsonify(code=200, message='登录成功', data={'token': token})


# 获取用户基本信息
@auth.get('/info')
@jwt_required()
def info():
    id = get_jwt_identity().get('user_id')
    user_ORM = UserModel.query.get(id)
    user = model_to_dict(user_ORM)
    user.pop('password')
    user.pop('salt')
    user['roles'] = [u.code for u in user_ORM.roles]

    # 过滤按钮权限
    def perms(per=[]):
        def inner():
            nonlocal per
            for role in user_ORM.roles:
                perm = [m.perm for m in role.menus if m.type == 3]
                per = per + perm
            return per

        return list(set(inner()))

    user['perms'] = perms()
    return jsonify(code=200, message='获取成功', data=user)


@auth.post('/logout')
@jwt_required()
def logout():
    return jsonify({
        'code': 200,
        'data': None,
        'message': '退出成功'
    })
